/**
 * @fileoverview Jasmine JsTestDriver Adapter.
 * @author misko@hevery.com (Misko Hevery)
 * @author olmo.maldonado@gmail.com (Olmo Maldonado)
 */
(function() {


    var Env = function(onTestDone, onComplete) {
        jasmine.Env.call(this);

        this.specFilter = function(spec) {
            if (!this.exclusive) return true;
            var blocks = spec.queue.blocks, l = blocks.length;
            for (var i = 0; i < l; i++) if (blocks[i].func.exclusive >= this.exclusive) return true;
            return false;
        };

        this.reporter = new Reporter(onTestDone, onComplete);
    };
    jasmine.util.inherit(Env, jasmine.Env);

// Here we store:
// 0: everyone runs
// 1: run everything under ddescribe
// 2: run only iits (ignore ddescribe)
    Env.prototype.exclusive = 0;


    Env.prototype.execute = function() {
        collectMode = false;
        playback();
        jasmine.Env.prototype.execute.call(this);
    };


    var Reporter = function(onTestDone, onComplete) {
        this.onTestDone = onTestDone;
        this.onComplete = onComplete;
        this.reset();
    };
    jasmine.util.inherit(Reporter, jasmine.Reporter);


    Reporter.formatStack = function(stack) {
        var line, lines = (stack || '').split(/\r?\n/), l = lines.length, frames = [];
        for (var i = 0; i < l; i++) {
            line = lines[i];
            if (line.match(/\/jasmine[\.-]/)) continue;
frames.push(line.replace(/https?:\/\/\w+(:\d+)?\/test\//, '').replace(/^\s*/, '			'));
        }
                                  return frames.join('\n');
    };


    Reporter.prototype.reset = function() {
        this.specLog = jstestdriver.console.log_ = [];
    };


    Reporter.prototype.log = function(str) {
        this.specLog.push(str);
    };


    Reporter.prototype.reportSpecStarting = function() {
        this.reset();
        this.start = +new Date();
    };


    Reporter.prototype.reportSpecResults = function(spec) {
        var elapsed = +new Date() - this.start, results = spec.results();

        if (results.skipped) return;

        var item, state = 'passed', items = results.getItems(), l = items.length, messages = [];
        for (var i = 0; i < l; i++) {
            item = items[i];
            if (item.passed()) continue;
            state = (item.message.indexOf('AssertionError:') != -1) ? 'error' : 'failed';
            messages.push( {
message: item + '',
name: item.trace.name,
stack: Reporter.formatStack(item.trace.stack)
            });
        }

        this.onTestDone(new jstestdriver.TestResult(
                            spec.suite.getFullName(),
                            spec.description,
                            state,
                            jstestdriver.angular.toJson(messages),
                            this.specLog.join('\n'),
                            elapsed
                        ));
    };


    Reporter.prototype.reportRunnerResults = function() {
        this.onComplete();
    };


    var collectMode = true, intercepted = {};

    describe = intercept('describe');
    beforeEach = intercept('beforeEach');
    afterEach = intercept('afterEach');

    var JASMINE_TYPE = 'jasmine test case';
    TestCase('Jasmine Adapter Tests', null, JASMINE_TYPE);

    jstestdriver.pluginRegistrar.register( {

name: 'jasmine',

getTestRunsConfigurationFor: function(testCaseInfos, expressions, testRunsConfiguration) {
            for (var i = 0; i < testCaseInfos.length; i++) {
                if (testCaseInfos[i].getType() == JASMINE_TYPE) {
                    testRunsConfiguration.push(new jstestdriver.TestRunConfiguration(testCaseInfos[i], []));
                }
            }
            return false; // allow other TestCases to be collected.
        },

runTestConfiguration: function(config, onTestDone, onComplete) {
            if (config.getTestCaseInfo().getType() != JASMINE_TYPE) return false;
            (jasmine.currentEnv_ = new Env(onTestDone, onComplete)).execute();
            return true;
        },

onTestsFinish: function() {
            jasmine.currentEnv_ = null;
            collectMode = true;
        }

    });

    function intercept(method) {
        var bucket = intercepted[method] = [], method = window[method];
        return function(desc, fn) {
            if (collectMode) bucket.push(function() {
                method(desc, fn);
            });
            else method(desc, fn);
        };
    }

    function playback() {
        for (var method in intercepted) {
            var bucket = intercepted[method];
            for (var i = 0, l = bucket.length; i < l; i++) bucket[i]();
        }
    }

})();

var ddescribe = function(name, fn) {
    var env = jasmine.getEnv();
    if (!env.exclusive) env.exclusive = 1; // run ddescribe only
    describe(name, function() {
        var oldIt = it;
        it = function(name, fn) {
            fn.exclusive = 1; // run anything under ddescribe
            env.it(name, fn);
        };

        try {
            fn.call(this);
        }
        finally {
            it = oldIt;
        };
    });
};

var iit = function(name, fn) {
    var env = jasmine.getEnv();
    env.exclusive = fn.exclusive = 2; // run only iits
    env.it(name, fn);
};

// Patch Jasmine for proper stack traces
jasmine.Spec.prototype.fail = function (e) {
    var result = new jasmine.ExpectationResult( {
passed: false,
message: e ? jasmine.util.formatException(e) : 'Exception'
    });
    if(e) result.trace = e;
    this.results_.addResult(result);
};
